import { _decorator, Component, Node, gfx, Mesh, MeshRenderer, renderer, size, Size, utils, v2, v3, v4, Vec2, Vec3, Vec4, Quat } from 'cc';

/**用于合并相同模型的组件 */
export class MergetMesh {
    public mergeCount = 110; //最大上限
    public usedCount = 0;    //已使用的个数

    protected msr: MeshRenderer = null;

    protected meshData: { positions: number[], normals: number[], minPos?: Vec3, maxPos?: Vec3, colors?: number[], uvs: number[], indices: number[], customAttributes?: any[] } = null;
    //记录当前部分的所有的格子信息
    public mergeItemArr: MergeItem[] = [];
    protected finishCb = null;

    constructor(cb) {
        this.finishCb = cb;
    }

    //#region -----模型网格数据记录---------
    /**指定模型的网格数据 */
    protected static baseMeshData: { [msName: string]: any } = {};
    //

    protected static recordMeshData(mesh: Mesh) {
        let data: any = {};
        data.positions = mesh.readAttribute(0, gfx.AttributeName.ATTR_POSITION);
        data.normals = mesh.readAttribute(0, gfx.AttributeName.ATTR_NORMAL);
        data.tangents = mesh.readAttribute(0, gfx.AttributeName.ATTR_TANGENT);
        data.uvs = mesh.readAttribute(0, gfx.AttributeName.ATTR_TEX_COORD);
        data.colors = mesh.readAttribute(0, gfx.AttributeName.ATTR_COLOR);
        data.indices = mesh.readIndices(0);
        //坐标系旋转
        // this.rotatePos(data.positions);   
        // this.rotatePos(data.normals);
        // this.rotatePos(data.tangents);
        return data;
    }
    /**X轴旋转-90度 */
    protected static rotatePos(arr: number[]) {
        let count = arr.length / 3;
        for (let i = 0; i < count; ++i) {
            let index = i * 3 + 1;
            let t = arr[index];
            arr[index] = arr[index + 1];
            arr[index + 1] = -t;
        }
    }
    //#endregion

    // #region -------流程------

    public reset(): void {
        this.resetMat();
        this.resetMergeItems();
    }

    public setData(d: { mesh: Mesh, meshRenderer: MeshRenderer }): void {
        this.msr = d.meshRenderer;
        this.mergeMesh(d.mesh);
        this.setMergeItem();
        this.setMats();
    }

    public customUpdate(dt: number): void {
        this.updateMergeItem(dt);
        this.updateMat(dt);
    }

    // #endregion

    //#region --------合并网格---------
    //计数
    protected meshItemCount: number = 0;
    protected mergeMesh(ms: Mesh) {
        //记录数据        
        if (!MergetMesh.baseMeshData[ms._uuid]) {
            MergetMesh.baseMeshData[ms._uuid] = MergetMesh.recordMeshData(ms);
        }

        this.meshData = {
            positions: [],
            normals: [],
            uvs: [],
            indices: [],
            // minPos: v3(-cw, 0, ch),
            // maxPos: v3(cw, 0, -ch),
            customAttributes: [
                {
                    //v4 x 表示索引, y:表示使用的格子uv偏移
                    attr: {
                        name: "a_animData",
                        format: gfx.Format.RGBA32F,
                        isNormalized: false,
                        stream: 0,
                        isInstanced: false,
                        location: 0,
                        //记录属性的偏移量
                        customOffset: 0,
                    },
                    values: [],
                },
            ],
        };

        for (let i = 0; i < this.mergeCount; i++) {
            this.pushSubMesh(this.meshData, ms._uuid)
        }

        this.msr.mesh = utils.createMesh(this.meshData);
    }
    protected pushSubMesh(data, msName) {
        let meshData = MergetMesh.baseMeshData[msName];
        let vertCount = meshData.positions.length / 3;
        let index = data.positions.length / 3;

        this.copyArr(data.positions, meshData.positions);
        this.copyArr(data.normals, meshData.normals);
        this.copyArr(data.uvs, meshData.uvs);
        this.pushIndices(data, meshData.indices, index);

        this.pushMeshAnimData(data, this.meshItemCount, vertCount);
        this.meshItemCount += 1;
    }
    protected pushIndices(data, indices, offset) {
        for (let i = 0, c = indices.length; i < c; ++i) {
            data.indices.push(indices[i] + offset);
        }
    }
    protected pushMeshAnimData(data, index, count) {
        let values0 = data.customAttributes[0].values;
        for (let i = 0; i < count; ++i) {
            values0.push(index, 0, 0, 0);
        }
    }
    //#endregion

    //#region --------材质-----------
    //位移+缩放
    private handleTrans = 0;
    private transArr: Vec4[]; // xyz表示坐标 w表示缩放
    private isTransDirty = false;

    //旋转
    private handleRotat = 0;
    private rotateArr: Vec4[];
    private isRotateDirty = false;

    private pass: renderer.Pass = null;

    protected setMats() {
        let mat = this.msr.getMaterialInstance(0);
        this.pass = mat.passes[0];
        //1.位移+缩放
        this.handleTrans = this.pass.getHandle('transData');
        this.transArr = [];
        //2.旋转
        this.handleRotat = this.pass.getHandle('rotateData');
        this.rotateArr = [];
        //初始化参数-默认集中在原点位置
        for (let index = 0; index < this.mergeCount; index++) {
            this.transArr.push(v4(0, 0, 0, 0));
            this.rotateArr.push(v4(0, 0, 0, 0));
        }
        this.applyTrans();
        this.applyRotate();
    }

    private resetMat(): void {
        for (let i = 0; i < this.mergeCount; i++) {
            this.transArr[i].set(0, 0, 0, 0);
            this.rotateArr[i].set(0, 0, 0, 0);
        }

        this.applyTrans();
        this.applyRotate();
    }
    private updateMat(dt) {
        if (this.isTransDirty) {
            this.applyTrans();
            this.isTransDirty = false;
        }
        if (this.isRotateDirty) {
            this.applyRotate();
            this.isRotateDirty = false;
        }
    }

    private applyTrans() {
        this.pass && this.pass.setUniformArray(this.handleTrans, this.transArr);
    }

    private applyRotate() {
        this.pass && this.pass.setUniformArray(this.handleRotat, this.rotateArr);
    }

    //#endregion  

    //#region --------格子属性同步------------    
    private setMergeItem() {
        if (this.mergeItemArr.length == 0) {
            for (let i = 0; i < this.mergeCount; i++) {
                this.mergeItemArr.push(new MergeItem(i));
            }
        }
    }
    /**重置 */
    private resetMergeItems() {
        this.usedCount = 0;
        for (let i = 0; i < this.mergeCount; i++) {
            this.mergeItemArr[i].setActive(false);
        }
        this.updateMergeItem();
        this.applyTrans();
    }

    /**获取空闲的item */
    public getMergeItems(outArr: MergeItem[], count: number): boolean {
        this.resetMergeItems();

        let n = 0;
        for (let i = 0; i < this.mergeItemArr.length; i++) {
            const e = this.mergeItemArr[i];
            if (n >= count) break;
            if (e && !e.isActive) {
                outArr.push(e);
                e.setActive(true);
                n++;
                this.usedCount++;
            }
        }
        if (outArr.length == 0) debugger
        return true;
    }

    //同步信息到材质参数中-标脏
    private updateMergeItem(dt?) {
        this.usedCount = 0;
        for (let i = 0; i < this.mergeItemArr.length; i++) {
            const e = this.mergeItemArr[i];
            const _id = e.id;
            if (e.isDirty) {
                // if (this.transArr[_id].x !== e.pos.x || this.transArr[_id].y !== e.pos.y ||
                //     this.transArr[_id].z !== e.pos.z || this.transArr[_id].w !== e.scale) {
                // }
                this.transArr[_id].set(e.pos.x, e.pos.y, e.pos.z, e.scale);
                this.isTransDirty = true;
                // if (this.rotateArr[_id].x !== e.rot.x || this.rotateArr[_id].y !== e.rot.y ||
                //     this.rotateArr[_id].z !== e.rot.z || this.rotateArr[_id].w !== e.rot.w) {
                // }
                this.rotateArr[_id].set(e.rot);
                this.isRotateDirty = true;
                e.isDirty = false;
                this.usedCount++;
            }
        }
        if (this.usedCount == 0) {
            this.animFinished();
        }
    }
    //动画完成
    public animFinished() {
        this.finishCb && this.finishCb();
    }

    //#endregion

    //#region --------事件------------

    //#endregion
    protected copyArr(a, b) {
        for (let i = 0, c = b.length; i < c; ++i) {
            a.push(b[i]);
        }
    }
}


export class MergeItem {
    id = 0; //对应参数下标
    pos = v3();
    scale = 1;
    rot = v4();
    isActive = false;
    isDirty = false;
    constructor(id) {
        this.id = id;
    }

    setPos(p: Vec3) {
        this.pos.set(p);
        this.isDirty = true;
    }
    //四元数旋转
    setRot(rt: Vec4) {
        this.rot.set(rt);
        this.isDirty = true;
    }
    setScale(s: number) {
        this.scale = s;
        this.isDirty = true;
    }
    setActive(isActive: boolean) {
        this.isActive = isActive;
        this.scale = this.isActive ? this.scale : 0;
        this.isDirty = true;
    }

}